package com.org.service.impl.dev;

import com.github.pagehelper.Page;
import com.org.core.mybatis.PageUtil;
import com.org.core.mybatis.SqlUtil;
import com.org.core.util.DateUtil;
import com.org.core.util.ObjectUtil;
import com.org.dao.dev.DevDataBackupConfigMapper;
import com.org.dao.dev.DevDataBackupMapper;
import com.org.dao.dev.DevTableMapper;
import com.org.entity.base.PageRequest;
import com.org.entity.base.PageResult;
import com.org.entity.dev.DevDataBackupConfig;
import com.org.entity.dev.DevTableColumn;
import com.org.service.dev.DevDataBackupConfigService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import tk.mybatis.mapper.entity.Example;

import javax.sql.DataSource;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class DevDataBackupConfigServiceImpl implements DevDataBackupConfigService {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private DevDataBackupConfigMapper devDataBackupConfigMapper;

    @Autowired
    private DataSource dataSource;

    @Autowired
    private DevTableMapper devTableMapper;

    @Autowired
    private DevDataBackupMapper devDataBackupMapper;

    @Override
    public int addDevDataBackupConfigInfo(DevDataBackupConfig devDataBackupConfig) {
        return devDataBackupConfigMapper.insert(devDataBackupConfig);
    }

    @Override
    public int updateDevDataBackupConfigInfo(DevDataBackupConfig devDataBackupConfig) {
        return devDataBackupConfigMapper.updateByPrimaryKeySelective(devDataBackupConfig);
    }

    @Override
    public int delDevDataBackupConfigInfo(String id) {
        return devDataBackupConfigMapper.deleteByPrimaryKey(id);
    }

    @Override
    public int delDevDataBackupConfigList(String ids) {
        String[] idArray = ids.split(",");
        Example example = new Example(DevDataBackupConfig.class);
        example.createCriteria().andIn("id", Arrays.asList(idArray));
        return devDataBackupConfigMapper.deleteByExample(example);
    }

    @Override
    public DevDataBackupConfig getDevDataBackupConfigInfo(String id) {
        return devDataBackupConfigMapper.selectByPrimaryKey(id);
    }

    @Override
    public List<DevDataBackupConfig> getDevDataBackupConfigList(String keyword) {
        return getDevDataBackupConfigExample(keyword);
    }

    @Override
    public PageResult<DevDataBackupConfig> getDevDataBackupConfigPageList(String keyword, PageRequest pageRequest) {
        Page<?> page = PageUtil.startPageAllowNull(pageRequest.getPageNum(), pageRequest.getPageSize());
        return new PageResult<>(getDevDataBackupConfigExample(keyword), page.getTotal());
    }

    @Override
    public List<DevDataBackupConfig> getAllNeedBackupConfig() {
        Example example = new Example(DevDataBackupConfig.class);
        example.createCriteria().andNotEqualTo("backupDays", -1);
        return devDataBackupConfigMapper.selectByExample(example);
    }

    @Transactional
    @Override
    public Map<String,Object> backupData(DevDataBackupConfig sysDataBackupConfig) {
        Map<String,Object> map = new HashMap<>(2);
        map.put("flag",false);
        map.put("count",0);
        logger.info("<<------------------------------------------------------------------------>>");
        String tableSchema = SqlUtil.getTableSchema(dataSource);
        Date now = DateUtil.getNowDate();
        String yesterday =DateUtil.addDate(now,-1);
        String fromTable = sysDataBackupConfig.getFromTable();
        String toTable = sysDataBackupConfig.getToTable();
        String timeColumn = sysDataBackupConfig.getTimeColumn();
        if (ObjectUtil.isNotNull(sysDataBackupConfig.getLastBackupDate())) {
            //当前时间减去上次备份时间
            int subDay = DateUtil.dateSubDate(now, sysDataBackupConfig.getLastBackupDate());
            //相减的天数 小于 几天备份一次  则 不做备份
            if (subDay < sysDataBackupConfig.getBackupDays()) {
                return map;
            }
        }
        logger.info("{}表 [备份] 到 {}表==>> 开始", fromTable, toTable);
        //获取两个表的字段
        List<DevTableColumn> fromTableColumns = devTableMapper.getDevTableColumns(tableSchema, fromTable);
        List<DevTableColumn> toTableColumns = devTableMapper.getDevTableColumns(tableSchema, toTable);
        //校验表是否存在 如果fromTableColumns和toTableColumns为空，则表不存在
        if (CollectionUtils.isEmpty(fromTableColumns) || CollectionUtils.isEmpty(toTableColumns)) {
            logger.info("{}表或{}表不存在", fromTable, toTable);
            return map;
        }
        //查找数据源表是否有数据
        int count = devDataBackupMapper.fromTableNeedBackupData(fromTable, timeColumn, yesterday, yesterday);
        if (count == 0) {
            logger.info("{}查找到需要备份的数据行数为零", fromTable);
            return map;
        }
        //对两个表的字段进行校验 （Ⅰ.fromtable的字段数 > toTable的字段 II.fromtable的字段数 < toTable的字段）
        if (fromTableColumns.size() > toTableColumns.size()) {
            logger.info("{}表字段数 [大于] {}表，请及时同步表结构", fromTable, toTable);
        }
        if (fromTableColumns.size() < toTableColumns.size()) {
            logger.info("{}表字段数 [小于] {}表，请及时同步表结构", fromTable, toTable);
        }
        //取字段交集
        List<DevTableColumn> intersection = fromTableColumns.stream().filter(item -> find(item.getName(), toTableColumns) > -1).collect(Collectors.toList());
        //备份数据
        int backup = devDataBackupMapper.dataBackup(fromTable, toTable, timeColumn, yesterday, yesterday, intersection);
        if (backup > 0) {
            logger.info("{}表 [备份] 到 {}表==>> 成功", fromTable, toTable);
            //删除数据来源表数据
            int deleteData = devDataBackupMapper.deleteFromTableData(fromTable, timeColumn, yesterday, yesterday);
            if (deleteData > 0) {
                //更新配置上次备份时间字段
                sysDataBackupConfig.setLastBackupDate(now);
                devDataBackupConfigMapper.updateByPrimaryKeySelective(sysDataBackupConfig);
                logger.info("{}表旧数据[移除] 成功", fromTable, toTable);
            } else {
                logger.info("{}表旧数据[移除] 失败", fromTable, toTable);
            }
            logger.info("{}表 [备份] 到 {}表==>> 结束", fromTable, toTable);
            map.put("flag",true);
            map.put("count",backup);
            return map;
        } else {
            logger.info("{}表 [备份] 到 {}表==>> 失败", fromTable, toTable);
            return map;
        }
    }

    /**
     * 封装取字段交集方法
     *
     * @param name
     * @param list
     * @return
     */
    private int find(String name, List<DevTableColumn> list){
        int res = -1;
        for(int i = 0; i < list.size(); i ++){
            if (list.get(i).getName().equals(name)){
                res = i;
                break;
            }
        }
        return res;
    }

    /**
     * 获取列表、分页列表公用方法
     *
     * @param keyword
     * @return
     */
    private List<DevDataBackupConfig> getDevDataBackupConfigExample(String keyword) {
        Example example = new Example(DevDataBackupConfig.class);
        example.createCriteria().andLike("fromTable", SqlUtil.likeEscapeH(keyword));
        example.createCriteria().andLike("toTable", SqlUtil.likeEscapeH(keyword));
        example.orderBy("addTime").desc();
        return devDataBackupConfigMapper.selectByExample(example);
    }
}
